<template>
  <div class="layout-container">
    <!-- 侧边栏 -->
    <SideBar @tab-change="handleTabChange" />
    
    <!-- 主内容区 -->
    <div class="main-content">
      <div class="main-header">
        <span class="main-title">AI对话 - 语音模式</span>
      </div>
      <div class="main-divider"></div>
      
      <div class="main-body">
        <!-- 仅语音模式：显示亲属头像 -->
        <div class="digital-human-section">
          <div class="avatar-container audio-only">
            <img v-if="relativeInfo.avatar" :src="relativeInfo.avatar" alt="relative" class="digital-human-image" />
            <div v-else class="avatar-placeholder"></div>
          </div>
          
          <!-- 连接状态指示器 -->
          <div class="connection-status" :class="{ connected: connected }">
            <div class="status-dot"></div>
            <span class="status-text">{{ statusText }}</span>
          </div>
          
          <!-- 错误状态显示 -->
          <div v-if="hasError" class="error-status">
            <div class="error-message">{{ errorMessage }}</div>
            <button class="retry-btn" @click="retryConnection" :disabled="isInitializing">
              {{ isInitializing ? '重试中...' : '重试连接' }}
            </button>
          </div>
        </div>

        <!-- 聊天记录区域 -->
        <div class="chat-history" :class="{ expanded }">
          <div class="chat-controls">
            <button class="expand-toggle" @click="expanded = !expanded">
              {{ expanded ? '收起对话' : '展开对话' }}
            </button>
          </div>
          <div class="messages-container" ref="messagesContainer">
            <div 
              v-for="message in orderedMessages" 
              :key="message.id"
              class="message"
              :class="message.type"
            >
              <span class="message-dot"></span>
              <div class="message-content">
                {{ message.displayText !== undefined ? message.displayText : message.text }}
              </div>
            </div>
            
            <!-- AI正在输入提示 -->
            <div v-if="isAITyping" class="message ai typing">
              <div class="message-content">
                <div class="typing-indicator">
                  <span></span>
                  <span></span>
                  <span></span>
                </div>
              </div>
            </div>
          </div>
        </div>

        <!-- 控制按钮区域 -->
        <div class="controls">
          <button class="control-btn end-call-btn" @click="endCall">
            <uni-icons type="phone" size="24" color="#fff" />
          </button>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount, nextTick, onUnmounted, watch } from 'vue'
import { useRouter, onBeforeRouteLeave, useRoute } from 'vue-router'
import { go } from '@/utils/nav.js'
import { useUserStore } from '@/store'
import { useRelativeStore } from '@/store/modules/relative'
import SideBar from '/pages/pc/sideBar.vue'
import { startAgent, stopAgent, ping } from '@/api/pc/ten'
import { getRelativeProfile } from '@/api/pc/elderly'
import { rtcManager } from '@/plugins/rtc'
import config from '@/config'
import { getRTCToken } from '@/api/pc/ten'

const router = useRouter()
const route = useRoute()
const userStore = useUserStore()
const relativeStore = useRelativeStore()

// 响应式数据
const connected = ref(false)
const messages = ref([])
const isAITyping = ref(false)
const errorMessage = ref('')
const messagesContainer = ref(null)
// 🎯 直接从路由参数初始化，使用空字符串避免闪现
const relativeInfo = ref({
  name: route.query.roleName || '亲属',
  relationship: route.query.roleRelationship || '家人',
  avatar: route.query.avatar || '',  // 使用空字符串，避免显示默认图片
  fullRoleData: null
})
const expanded = ref(false)
const statusText = ref('初始化中...')
const isInitializing = ref(false)
const hasError = ref(false)

// 打字机效果相关状态
const typingMessages = ref(new Map())
const typingTimers = ref(new Map())

let heartbeatTimer = null

// 状态管理变量
const isCleaningUp = ref(false)
const isInitialized = ref(false)

// 初始化 RTC 聊天服务
const initRTCChatService = async () => {
  try {
    if (!rtcManager || !rtcManager.client) {
      console.warn('RTC manager not ready, skipping chat service initialization')
      return
    }

    rtcManager.client.on("stream-message", (uid, stream) => {
      try {
        const decoder = new TextDecoder("utf-8");
        const decoded = decoder.decode(stream);
        
        const parts = decoded.split("|");
        if (parts.length < 4) {
          console.warn('Invalid stream message format:', decoded);
          return;
        }

        const [message_id, partIndexStr, totalPartsStr, content] = parts;
        const part_index = parseInt(partIndexStr, 10);
        const total_parts = totalPartsStr === "???" ? -1 : parseInt(totalPartsStr, 10);
        
        if (!window.messageCache) {
          window.messageCache = {};
          window.messageTimeoutMap = {};
        }

        const chunk = { message_id, part_index, total_parts, content };

        if (!window.messageCache[message_id]) {
          window.messageCache[message_id] = [];
          window.messageTimeoutMap[message_id] = setTimeout(() => {
            console.warn(`Message ${message_id} timeout, cleaning up`);
            delete window.messageCache[message_id];
            delete window.messageTimeoutMap[message_id];
          }, 10000);
        }

        window.messageCache[message_id].push(chunk);

        const sorted = window.messageCache[message_id].sort((a, b) => a.part_index - b.part_index);
        const currentMessage = sorted.map(c => c.content).join("");
        
        try {
          const decodedMessage = atob(currentMessage);
          const messageData = JSON.parse(decodedMessage);
          const { stream_id, is_final, text, text_ts } = messageData;
          
          const isAgent = Number(stream_id) !== Number(userStore.uid);
          
          if (text && text.trim().length > 0) {
            if (isAgent) {
              updateStreamingMessageByUser(stream_id, text, is_final, Number(text_ts) || Date.now(), 'ai');
            } else {
              updateStreamingMessageByUser(stream_id, text, is_final, Number(text_ts) || Date.now(), 'user');
            }
          }
        } catch (parseError) {
          // 消息还不完整，继续等待
        }

        if (total_parts !== -1 && window.messageCache[message_id].length === total_parts) {
          clearTimeout(window.messageTimeoutMap[message_id]);
          delete window.messageTimeoutMap[message_id];
          delete window.messageCache[message_id];
        }
      } catch (error) {
        console.error('Failed to process stream message:', error);
      }
    });
  } catch (error) {
    console.error('Failed to initialize RTC Chat Service:', error)
  }
}

// 初始化连接
const initializeConnection = async () => {
  if (isInitialized.value || isInitializing.value) return
  
  isInitializing.value = true
  hasError.value = false
  errorMessage.value = ''
  
  try {
    if (!userStore.channelName || !userStore.uid || !userStore.requestId) {
      if (userStore.id) {
        userStore.generateTenIds(userStore.id)
      } else {
        throw new Error('用户ID不存在，请重新登录')
      }
    }

    await getRelativeInfo()
    
    try {
      await initRTC()
    } catch (error) {
      console.warn('RTC initialization failed:', error)
    }
    
    await startAgentService()
    startHeartbeat()
    
    try {
      await initRTCChatService()
    } catch (error) {
      console.warn('RTC Chat Service initialization failed:', error)
    }
    
    connected.value = true
    isInitialized.value = true
    hasError.value = false
    statusText.value = '已连接'
  } catch (error) {
    console.error('Failed to initialize connection:', error)
    errorMessage.value = '连接失败: ' + (error.message || '未知错误')
    hasError.value = true
    statusText.value = '连接失败'
    
    try {
      await cleanup(false)
    } catch (cleanupError) {
      console.error('Failed to cleanup after initialization error:', cleanupError)
    }
    
    throw error
  } finally {
    isInitializing.value = false
  }
}

// 初始化RTC
const initRTC = async (maxRetries = 3) => {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      if (!rtcManager) {
        throw new Error('rtcManager not available')
      }

      const rtcTokenResp = await getRTCToken(userStore.channelName, userStore.uid)
      const rtcToken = rtcTokenResp.data?.token
      
      if (!rtcToken) {
        throw new Error('Failed to get RTC token')
      }

      await rtcManager.init({
        appId: config.rtc.appId,
        channel: userStore.channelName,
        token: rtcToken,
        uid: parseInt(userStore.uid)
      })

      if (rtcManager && rtcManager.client) {
        rtcManager.client.on('user-published', async (user, mediaType) => {
          try {
            await rtcManager.client.subscribe(user, mediaType)
            if (mediaType === 'audio') {
              // 仅语音模式：正常播放音频
              if (user && user.audioTrack && typeof user.audioTrack.play === 'function') {
                user.audioTrack.play()
              }
            }
          } catch (e) {
            console.error('subscribe remote user failed:', e)
          }
        })
      }

      await rtcManager.createMicrophoneAudioTrack()
      await rtcManager.join()
      
      await new Promise(resolve => setTimeout(resolve, 1000))
      
      return
    } catch (error) {
      console.error(`RTC initialization attempt ${attempt} failed:`, error)
      
      if (attempt === maxRetries) {
        throw error
      }
      
      await new Promise(resolve => setTimeout(resolve, attempt * 1000))
    }
  }
}

// 根据角色性别获取对应的语音类型
const getVoiceTypeByGender = (gender) => {
  const voiceTypes = {
    '男': 'ICL_zh_male_yangyang_v1_tob',
    '女': 'S_VYJ6wIGu1',
    'male': 'ICL_zh_male_yangyang_v1_tob',
    'female': 'S_VYJ6wIGu1',
    '1': 'ICL_zh_male_yangyang_v1_tob',
    '0': 'S_VYJ6wIGu1'
  }
  return voiceTypes[gender] || voiceTypes['男']
}

const getClusterByGender = (gender) => {
  const clusters = {
    '男': 'volcano_tts',
    '女': 'volcano_icl',
    'male': 'volcano_tts',
    'female': 'volcano_icl',
    '1': 'volcano_tts',
    '0': 'volcano_icl'
  }
  return clusters[gender] || clusters['男']
}

// 启动Agent服务
const startAgentService = async () => {
  if (!userStore.channelName || !userStore.uid || !userStore.requestId) {
    throw new Error(`缺少必要字段`)
  }
  
  try {
    const roleGender = relativeInfo.value.fullRoleData?.gender || '男'
    const voiceType = getVoiceTypeByGender(roleGender)
    const cluster = getClusterByGender(roleGender)

    console.log(`启动Agent服务 - 角色性别: ${roleGender}, 语音类型: ${voiceType}`)
    
    const response = await startAgent({
      channelName: userStore.channelName,
      graphName: "voice_assistant",
      userUid: parseInt(userStore.uid),
      voice_type: voiceType,
      cluster: cluster
    })
    
    if (response.code === 0 || response.code === "0") {
      console.log(`Agent服务启动成功`)
    } else {
      throw new Error(response.message || 'Failed to start agent service')
    }
  } catch (error) {
    console.error('Failed to start agent service:', error)
    throw error
  }
}

// 心跳机制
const startHeartbeat = () => {
  stopHeartbeat()
  
  heartbeatTimer = setInterval(async () => {
    try {
      await ping(userStore.channelName)
    } catch (error) {
      console.error('Heartbeat ping failed:', error)
    }
  }, 10000)
}

const stopHeartbeat = () => {
  if (heartbeatTimer) {
    clearInterval(heartbeatTimer)
    heartbeatTimer = null
  }
}

// 计算属性
const orderedMessages = computed(() => messages.value)

// 打字机效果
const startTypingEffect = (messageId, fullText, baseSpeed = 120) => {
  if (typingTimers.value.has(messageId)) {
    clearTimeout(typingTimers.value.get(messageId))
  }
  
  typingMessages.value.set(messageId, '')
  
  let currentIndex = 0
  const totalLength = fullText.length
  
  const typeNextChar = () => {
    if (currentIndex < totalLength) {
      const currentText = fullText.substring(0, currentIndex + 1)
      typingMessages.value.set(messageId, currentText)
      
      const messageIndex = messages.value.findIndex(msg => msg.id === messageId)
      if (messageIndex !== -1) {
        messages.value[messageIndex].displayText = currentText
        messages.value[messageIndex].isTyping = true
      } else {
        stopTypingEffect(messageId)
        return
      }
      
      currentIndex++
      
      const currentChar = fullText[currentIndex - 1]
      let nextDelay = baseSpeed
      
      if (/[\u4e00-\u9fa5]/.test(currentChar)) {
        nextDelay = baseSpeed + 50
      } else if (/[a-zA-Z0-9]/.test(currentChar)) {
        nextDelay = baseSpeed - 20
      } else if (/[，。！？；：""''（）【】]/.test(currentChar)) {
        nextDelay = baseSpeed + 150
      } else if (/\s/.test(currentChar)) {
        nextDelay = baseSpeed + 30
      }
      
      const randomVariation = Math.random() * 30 - 15
      nextDelay = Math.max(nextDelay + randomVariation, 50)
      
      const timer = setTimeout(typeNextChar, nextDelay)
      typingTimers.value.set(messageId, timer)
      
      nextTick(() => {
        scrollToBottom()
      })
    } else {
      const messageIndex = messages.value.findIndex(msg => msg.id === messageId)
      if (messageIndex !== -1) {
        messages.value[messageIndex].displayText = fullText
        messages.value[messageIndex].isTyping = false
      }
      
      typingMessages.value.delete(messageId)
      typingTimers.value.delete(messageId)
      
      nextTick(() => {
        scrollToBottom()
      })
    }
  }
  
  typeNextChar()
}

const stopTypingEffect = (messageId) => {
  if (typingTimers.value.has(messageId)) {
    clearTimeout(typingTimers.value.get(messageId))
    typingTimers.value.delete(messageId)
  }
  typingMessages.value.delete(messageId)
}

// 滚动到底部
const scrollToBottom = () => {
  if (messagesContainer.value) {
    messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
  }
}

// 组装头像为可用的 Data URL
const buildAvatarDataUrl = (profile) => {
  if (!profile) return '/static/images/p1.png'
  const fileBase64 = profile.fileBase64
  if (!fileBase64) return '/static/images/p1.png'
  if (fileBase64.startsWith('data:')) return fileBase64
  const mimeType = profile.mimeType || 'image/png'
  return `data:${mimeType};base64,${fileBase64}`
}

// 加载亲属信息
const getRelativeInfo = async () => {
  try {
    if (route.query.avatar && route.query.relativeId) {
      const fullRoleData = {
        relativeId: route.query.relativeId || '',
        userId: route.query.userId || '',
        relationship: route.query.roleRelationship || '',
        name: route.query.roleName || '亲属',
        gender: route.query.gender || '',
        age: route.query.age || '',
        birthDate: route.query.birthDate || '',
        hometown: route.query.hometown || '',
        educationLevel: route.query.educationLevel || '',
        livecity: route.query.livecity || '',
        remark: route.query.remark || '',
        createBy: route.query.createBy || '',
        createTime: route.query.createTime || '',
        updateBy: route.query.updateBy || '',
        updateTime: route.query.updateTime || '',
        personalityProfile: null,
        audioRecordings: null,
        tempRelativeId: route.query.tempRelativeId || ''
      }

      relativeInfo.value = {
        name: route.query.roleName || '亲属',
        relationship: route.query.roleRelationship || '家人',
        avatar: route.query.avatar,
        fullRoleData: fullRoleData
      }

      const rid = route.query.relativeId
      if (rid) {
        relativeStore.setCurrentRelativeId(rid)
      }

      return
    }
    
    let rid = relativeStore.currentRelativeId
    if (!rid) {
      if (!relativeStore.list || relativeStore.list.length === 0) {
        await relativeStore.fetchList(userStore.id)
      }
      rid = relativeStore.list?.[0]?.id ?? relativeStore.list?.[0]?.relativeId ?? relativeStore.list?.[0]?.rid
      if (rid) {
        relativeStore.setCurrentRelativeId(rid)
      }
    }

    if (!rid) {
      relativeInfo.value = {
        name: '亲属',
        relationship: '家人',
        avatar: '/static/images/p1.png',
        fullRoleData: null
      }
      return
    }

    const res = await getRelativeProfile(rid)
    const data = res?.data || {}
    let avatarUrl = '/static/images/p1.png'
    
    if (Array.isArray(data.personalityProfile) && data.personalityProfile.length > 0) {
      avatarUrl = buildAvatarDataUrl(data.personalityProfile[0])
    } else if (typeof data.personalityProfile === 'object' && data.personalityProfile !== null) {
      avatarUrl = buildAvatarDataUrl(data.personalityProfile)
    } else if (data.avatar) {
      avatarUrl = data.avatar
    }

    relativeInfo.value = {
      name: data.name || '亲属',
      relationship: data.relationship || '家人',
      avatar: avatarUrl,
      fullRoleData: data
    }
  } catch (e) {
    console.warn('加载亲属信息失败，使用默认占位:', e)
    relativeInfo.value = {
      name: '亲属',
      relationship: '家人',
      avatar: '/static/images/p1.png',
      fullRoleData: null
    }
  }
}

// 处理侧边栏标签切换
const handleTabChange = (tabName) => {
  // 静默处理标签切换
}

// 结束通话
const endCall = async () => {
  try {
    await cleanup()
    go('/pages/pc/index')
  } catch (error) {
    console.error('End call error:', error)
    go('/pages/pc/index')
  }
}

// 清理资源
const cleanup = async (stopHeartbeatFlag = true) => {
  if (isCleaningUp.value) return
  
  isCleaningUp.value = true
  
  try {
    if (stopHeartbeatFlag) {
      stopHeartbeat()
    }
    
    // 清理 RTC 聊天服务
    try {
      if (window.messageTimeoutMap) {
        Object.values(window.messageTimeoutMap).forEach(timeout => clearTimeout(timeout));
        window.messageCache = {};
        window.messageTimeoutMap = {};
      }
    } catch (error) {
      console.error('Failed to cleanup RTC Chat Service:', error)
    }

    // 清理打字机效果定时器
    try {
      typingTimers.value.forEach(timer => clearTimeout(timer))
      typingTimers.value.clear()
      typingMessages.value.clear()
    } catch (error) {
      console.error('Failed to cleanup typing effects:', error)
    }

    // 清理 RTC
    if (rtcManager && connected.value) {
      try {
        await rtcManager.leave()
      } catch (error) {
        console.error('Failed to leave RTC:', error)
      }
    }
    
    // 停止 Agent 服务
    if (connected.value) {
      try {
        await stopAgent(userStore.channelName)
      } catch (error) {
        console.error('Failed to stop agent service:', error)
      }
    }
    
    // 重置状态
    connected.value = false
    isInitialized.value = false
    messages.value = []
    isAITyping.value = false
    errorMessage.value = ''
  } catch (error) {
    console.error('Cleanup error:', error)
    connected.value = false
  } finally {
    isCleaningUp.value = false
  }
}

// 流式消息更新
const updateStreamingMessageByUser = (userId, text, isFinal, time, role = 'ai') => {
  let lastFinalIndex = -1
  let lastNonFinalIndex = -1
  
  for (let i = messages.value.length - 1; i >= 0; i--) {
    const item = messages.value[i]
    if (!item) continue
    if (role === 'ai' && item.type !== 'ai') continue
    if (role === 'user' && item.type !== 'user') continue
    if (item.userId == userId && item.isFinal && lastFinalIndex === -1) {
      lastFinalIndex = i
    }
    if (item.userId == userId && !item.isFinal && lastNonFinalIndex === -1) {
      lastNonFinalIndex = i
    }
    if (lastFinalIndex !== -1 && lastNonFinalIndex !== -1) break
  }

  const messageId = `${role}-${userId}-${Date.now()}`
  const payload = {
    text,
    displayText: role === 'ai' ? '' : text,
    type: role === 'user' ? 'user' : 'ai',
    isFinal: !!isFinal,
    timestamp: Number(time) || Date.now(),
    id: messageId,
    userId,
    isTyping: role === 'ai' ? true : false
  }

  if (lastFinalIndex !== -1) {
    if (lastNonFinalIndex !== -1) {
      stopTypingEffect(messages.value[lastNonFinalIndex].id)
      messages.value[lastNonFinalIndex] = payload
    } else {
      messages.value.push(payload)
    }
  } else {
    if (lastNonFinalIndex !== -1) {
      stopTypingEffect(messages.value[lastNonFinalIndex].id)
      messages.value[lastNonFinalIndex] = payload
    } else {
      messages.value.push(payload)
    }
  }

  messages.value.sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0))

  if (role === 'ai' && isFinal && text && text.trim().length > 0) {
    startTypingEffect(messageId, text, 120)
  }

  nextTick(() => {
    scrollToBottom()
  })
}

// 重试初始化连接
const retryConnection = async () => {
  if (isInitializing.value) return
  
  try {
    hasError.value = false
    errorMessage.value = ''
    await initializeConnection()
  } catch (error) {
    console.error('Retry failed:', error)
    hasError.value = true
  }
}

// 组件生命周期
onMounted(async () => {
  try {
    // 🎯 优先从路由参数读取角色头像，避免显示默认 p1.png
    if (route.query.avatar) {
      relativeInfo.value.avatar = route.query.avatar
      relativeInfo.value.name = route.query.roleName || '亲属'
      relativeInfo.value.relationship = route.query.roleRelationship || '家人'
      console.log('✅ 从路由参数加载角色头像:', route.query.avatar)
    }
    
    await initializeConnection()
    
    watch(() => relativeStore.currentRelativeId, async (newVal, oldVal) => {
      if (newVal && newVal !== oldVal) {
        await getRelativeInfo()
      }
    })
  } catch (error) {
    console.error('Component mount failed:', error)
    errorMessage.value = '页面初始化失败，请刷新重试'
  }
})

onBeforeUnmount(() => {
  // 清理资源
})

onBeforeRouteLeave((to, from, next) => {
  if (connected.value && !isCleaningUp.value) {
    cleanup(true).then(() => {
      next()
    }).catch((error) => {
      console.error('Cleanup error during route leave:', error)
      next()
    })
  } else {
    next()
  }
})

onUnmounted(() => {
  if (!isCleaningUp.value) {
    cleanup()
  }
})

watch(expanded, (val) => {
  nextTick(() => {
    scrollToBottom()
  })
})
</script>

<style scoped>
/* 主容器样式 */
.layout-container {
  display: flex;
  height: 100vh;
  background-color: #1976ed;
  border-radius: 0;
  overflow: hidden;
  position: relative;
}

/* 主内容区样式 */
.main-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: #fff;
  border-radius: 24px 0 0 24px;
  padding: 0;
  overflow: hidden;
}

.main-header {
  height: 64px;
  display: flex;
  align-items: center;
  padding-left: 32px;
  background: #fff;
  font-size: 28px;
  font-weight: 600;
  border-bottom: 1px solid #f0f0f0;
  flex-shrink: 0;
}

.main-title {
  color: #222;
}

.main-body {
  flex: 1;
  background: #fff;
  padding: 20px 32px;
  display: flex;
  flex-direction: column;
  align-items: center;
  overflow-y: auto;
  min-height: 0;
}

/* 数字人显示区域 */
.digital-human-section {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: 20px;
  z-index: 1;
}

.avatar-container {
  width: 240px;
  height: 240px;
  border-radius: 50%;
  overflow: hidden;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.1);
  position: relative;
  background-color: #333;
  display: flex;
  align-items: center;
  justify-content: center;
}

.digital-human-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 50%;
  background-color: #333;
  display: block;
  position: relative;
  z-index: 1;
}

/* 头像占位符 - 避免闪现 */
.avatar-placeholder {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  z-index: 1;
}

/* 音频模式不显示加载指示器 */
.avatar-container.audio-only::before {
  display: none;
}

/* 连接状态指示器 */
.connection-status {
  position: absolute;
  bottom: -40px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(0, 0, 0, 0.7);
  color: white;
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 14px;
  z-index: 10;
}

.status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: #ff4757;
  animation: pulse 2s infinite;
}

.connection-status.connected .status-dot {
  background-color: #2ed573;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

.status-text {
  font-size: 12px;
  white-space: nowrap;
}

/* 聊天记录外框 */
.chat-history {
  width: 100%;
  max-width: none;
  background: #f5f8ff;
  border-radius: 18px;
  padding: 32px 24px 24px 24px;
  min-height: 200px;
  position: relative;
  margin: 0 auto 32px auto;
  box-shadow: none;
  max-height: 400px;
  overflow-y: hidden;
  transition: all 0.3s cubic-bezier(.4,0,.2,1);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  z-index: 10;
}

.chat-history.expanded {
  position: relative;
  margin-top: -200px;
  max-height: 80vh;
  overflow: hidden;
  z-index: 20;
}

.chat-history.expanded .messages-container {
  overflow-y: auto;
  max-height: calc(80vh - 80px);
}

/* 消息列表 */
.messages-container {
  display: flex;
  flex-direction: column;
  gap: 16px;
  height: 100%;
  overflow-y: hidden;
  justify-content: flex-end;
}

.chat-history.expanded .messages-container {
  overflow-y: auto;
  max-height: calc(80vh - 80px);
  justify-content: flex-start;
}

/* 单条消息 */
.message {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  background: none;
  box-shadow: none;
  padding: 0;
  flex-shrink: 0;
}

.message-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-top: 7px;
  flex-shrink: 0;
}

.message.user .message-dot {
  background: #ff9800;
}

.message.ai .message-dot {
  background: #1976ed;
}

.message-content {
  font-size: 16px;
  color: #222;
  background: none;
  padding: 0;
  border-radius: 0;
  line-height: 1.7;
  word-break: break-all;
}

/* 按钮组样式 */
.chat-controls {
  position: absolute;
  top: 15px;
  right: 20px;
  display: flex;
  gap: 10px;
  z-index: 30;
}

.expand-toggle {
  background: #1976ed;
  color: white;
  border: none;
  border-radius: 20px;
  padding: 8px 16px;
  font-size: 12px;
  cursor: pointer;
  transition: background-color 0.2s;
}

.expand-toggle:hover {
  background: #1565c0;
}

/* 正在输入指示器 */
.typing-indicator {
  display: flex;
  align-items: center;
  gap: 4px;
}

.typing-indicator span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background-color: #1976ed;
  animation: typing 1.4s infinite;
}

.typing-indicator span:nth-child(2) {
  animation-delay: 0.2s;
}

.typing-indicator span:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes typing {
  0%, 60%, 100% {
    opacity: 0.3;
    transform: scale(0.8);
  }
  30% {
    opacity: 1;
    transform: scale(1);
  }
}

/* 打字机光标效果 */
.typing-cursor {
  display: inline-block;
  width: 2px;
  height: 1.2em;
  background-color: #1976ed;
  margin-left: 2px;
  animation: blink 1s infinite;
  vertical-align: text-bottom;
}

@keyframes blink {
  0%, 50% { opacity: 1; }
  51%, 100% { opacity: 0; }
}

/* 空状态优化 */
.empty-tip {
  text-align: center;
  color: #666;
  padding: 60px 20px;
}

.empty-subtitle {
  font-size: 14px;
  color: #999;
  margin-top: 8px;
}

/* 消息操作按钮 */
.message-action {
  font-size: 12px;
  color: #1976ed;
  cursor: pointer;
  padding: 4px 8px;
  border-radius: 4px;
  transition: background-color 0.2s;
}

.message-action:hover {
  background-color: #e3f2fd;
}

/* 滚动条样式 */
.chat-history::-webkit-scrollbar {
  width: 6px;
}

.chat-history::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

.chat-history::-webkit-scrollbar-thumb {
  background: #c1c1c1;
  border-radius: 3px;
}

.chat-history::-webkit-scrollbar-thumb:hover {
  background: #a8a8a8;
}

/* 控制按钮区域 - 固定在底部 */
.controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: auto;
  margin-bottom: 16px;
  flex-shrink: 0;
}

/* 控制按钮样式 */
.control-btn {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.2s;
}

.end-call-btn {
  background-color: #ff4757;
  color: white;
}

.end-call-btn:hover {
  transform: scale(1.05);
  background-color: #ff3742;
}

/* 错误状态样式 */
.error-status {
  margin-top: 20px;
  text-align: center;
  padding: 16px;
  background: rgba(255, 71, 87, 0.1);
  border: 1px solid rgba(255, 71, 87, 0.3);
  border-radius: 12px;
  max-width: 400px;
}

.error-message {
  color: #ff4757;
  font-size: 14px;
  margin-bottom: 12px;
  line-height: 1.4;
}

.retry-btn {
  background: #ff4757;
  color: white;
  border: none;
  border-radius: 20px;
  padding: 8px 20px;
  font-size: 14px;
  cursor: pointer;
  transition: all 0.2s;
}

.retry-btn:hover:not(:disabled) {
  background: #ff3742;
  transform: translateY(-1px);
}

.retry-btn:disabled {
  background: #ccc;
  cursor: not-allowed;
  transform: none;
}
</style>

